package com.battery.system.service.battery.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayFundAuthOperationDetailQueryResponse;
import com.alipay.api.response.AlipayFundAuthOrderAppFreezeResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.battery.common.core.domain.AjaxResult;
import com.battery.common.enums.*;
import com.battery.common.utils.*;
import com.battery.common.utils.ali.AliPayEntity;
import com.battery.common.utils.ali.AliPayUtils;
import com.battery.common.utils.dev.WsDevUtils;
import com.battery.common.utils.wx.PayscoreUtils;
import com.battery.system.domain.*;
import com.battery.system.domain.BO.UsedBO;
import com.battery.system.domain.VO.UsedVO;
import com.battery.system.mapper.*;
import com.battery.system.service.battery.IIncomeService;
import com.battery.system.service.impl.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.battery.system.service.battery.IAuthUsedService;
import com.battery.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

/**
 * 租借授权Service业务层处理
 *
 * @author battery
 * @date 2021-01-22
 */
@Service
public class AuthUsedServiceImpl extends BaseServiceImpl<AuthUsed> implements IAuthUsedService {
    @Autowired
    private AuthUsedMapper authUsedMapper;


    @Autowired
    private UsedMapper usedMapper;

    @Autowired
    private UsedBasicsMapper usedBasicsMapper;

    @Autowired
    private StoreMapper storeMapper;


    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AppUserMapper appUserMapper;


    @Autowired
    private Sid sid;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private IIncomeService incomeService;


    /**
     * 查询租借授权
     *
     * @param usedId 租借授权ID
     * @return 租借授权
     */
    @Override
    public AuthUsed selectAuthUsedById(String usedId) {
        return authUsedMapper.selectAuthUsedById(usedId);
    }

    /**
     * 查询租借授权列表
     *
     * @param authUsed 租借授权
     * @return 租借授权
     */
    @Override
    public List<AuthUsed> selectAuthUsedList(AuthUsed authUsed) {
        return authUsedMapper.selectAuthUsedList(authUsed);
    }

    /**
     * 新增租借授权
     *
     * @param authUsed 租借授权
     * @return 结果
     */
    @Override
    public int insertAuthUsed(AuthUsed authUsed) {
        return authUsedMapper.insertAuthUsed(authUsed);
    }

    /**
     * 修改租借授权
     *
     * @param authUsed 租借授权
     * @return 结果
     */
    @Override
    public int updateAuthUsed(AuthUsed authUsed) {
        return authUsedMapper.updateAuthUsed(authUsed);
    }

    /**
     * 删除租借授权对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteAuthUsedByIds(String ids) {
        return authUsedMapper.deleteAuthUsedByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除租借授权信息
     *
     * @param usedId 租借授权ID
     * @return 结果
     */
    @Override
    public int deleteAuthUsedById(String usedId) {
        return authUsedMapper.deleteAuthUsedById(usedId);
    }

    /**
     * 创建微信支付分订单
     *
     * @param appUser      租借用户
     * @param device       设备
     * @param storeInstall 门店配置信息
     * @param amount       金额
     * @return
     */
    @Override
    public BatteryJSONResult createrentbill(AppUser appUser, Device device, StoreInstall storeInstall, BigDecimal amount) {

        String sn = device.getSn();
        String usedId = sid.nextShort();

        // 生成唯一编码
        String order_number = GenerateSeqUtil.generateEndRadomCode();

        Date date = DateUtils.getNowDate();
        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
//        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setOrderNumber(order_number); // order_number
        used.setBorrowMode(BorrowModeEnum.FREE_DEPOSIT.type); // 免押租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);

        String storeName = "";
        if (storeInstall != null) {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        used.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        used.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);

        // 这里只是创建，而不是去租借
        UsedBasics basics = new UsedBasics();
        basics.setUsedId(usedId);
        basics.setRentDeviceId(device.getId());// 租借设备ID
        basics.setRentDeviceSn(sn); // 租借设备SN
        basics.setDevType(device.getDevType());
        usedBasicsMapper.insertUsedBasics(basics);


        AuthUsed authUsed = new AuthUsed();
        authUsed.setUsedId(usedId);
//        String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(12);
        String outOrderNo = order_number;
        authUsed.setOutOrderNo(outOrderNo);
        authUsed.setAmount(amount);
        authUsed.setCreateTime(date); // 免押订单创建时间
        authUsed.setAppUserId(appUser.getId());
        authUsedMapper.insertSelective(authUsed);


        if (StringUtils.isBlank(storeName)) {
            // TODO
            storeName = "-";
        }
        try {
            JSONObject createObj = new JSONObject();
            createObj.put("out_order_no", outOrderNo);
            createObj.put("appid", Constants.wxMinAppID); // 微信小程序APPID
            createObj.put("service_id", Constants.wxServiceId);// 微信支付分服务ID
            createObj.put("service_introduction", "免电共享充电宝"); // 微信小程序-服务信息
            JSONObject timeRangeObj = new JSONObject();
            timeRangeObj.put("start_time", "OnAccept");
            createObj.put("time_range", timeRangeObj);
            JSONObject locationObj = new JSONObject();
            locationObj.put("start_location", storeName);
            createObj.put("location", locationObj);
            createObj.put("notify_url", Constants.wxfreeNotifyUrl); // TODO 微信支付分回调地址

            JSONObject riskFundObj = new JSONObject();
            riskFundObj.put("name", "DEPOSIT");
            riskFundObj.put("amount", new BigDecimal(100).multiply(amount));
            createObj.put("risk_fund", riskFundObj);

            String mealMsg = "";
            String freeMsg = "";
            if (storeInstall != null) {
                if (storeInstall.getFreeM() > 0) {
                    freeMsg = storeInstall.getFreeM() + "分钟内免费,";
                }
                if (DevMealTimeEnum.HALF_HOUR.type.intValue() == storeInstall.getUnitTime().intValue()) {
                    mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/半小时,日封" + storeInstall.getDayMax() + "元";
                } else if (DevMealTimeEnum.FIFTEEN_MINUTES.type.intValue() == storeInstall.getUnitTime().intValue()) {
                    mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/15分钟,日封" + storeInstall.getDayMax() + "元";
                } else {
                    mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/小时,日封" + storeInstall.getDayMax() + "元";
                }
            } else {
                freeMsg = "2分钟内免费,";
                BigDecimal price = new BigDecimal(2);
                mealMsg = mealMsg + freeMsg + price + "元/小时,日封20元";
            }
            JSONArray arr = new JSONArray();
            JSONObject obj = new JSONObject();
            obj.put("name", "免电共享充电宝");
            obj.put("description", mealMsg); // 描述计费规则
            arr.add(0, obj);
            createObj.put("post_payments", arr);
            createObj.put("need_user_confirm", true);

            String merchantId = Constants.wxMerchantId;
            String certSerialNo = Constants.certSerialNo; // 微信支付证书序列号

            BatteryJSONResult result = PayscoreUtils.createrentbill(createObj, merchantId, certSerialNo, Constants.wx_cret_keyPath_apiclient_key);
            if (result.getCode() == 0) {
                // 创建微信支付分失败
                return result;
            }
            String body = (String) result.getData();
            JSONObject obj_ = JSONObject.parseObject(body);
            String package_ = obj_.getString("package"); // 跳转微信侧小程序订单数据
            if (StringUtils.isBlank(package_)) {
                return BatteryJSONResult.errorMsg("创建微信支付分订单失败");
            }
            String order_id = obj_.getString("order_id"); // 微信支付服务订单号
            String state = obj_.getString("state"); // 服务订单状态
            String state_description = obj_.getString("state_description"); // 订单状态说明

            // 更新微信支付分状态
            AuthUsed authUsedUpdate = new AuthUsed();
            authUsedUpdate.setUsedId(usedId);
            authUsedUpdate.setTicket(order_id);
            authUsedUpdate.setState(state);
            authUsedUpdate.setStateDescription(state_description);
            authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

            // 签名-前端调起微信支付分
            Map<String, String> reqData = new HashMap<>();
            reqData.put("timestamp", CommonUtils.getCurrentTimestamp() + "");
            reqData.put("sign_type", "HMAC-SHA256");
            reqData.put("package", package_);
            reqData.put("mch_id", merchantId);
            reqData.put("nonce_str", CommonUtils.generateUUID());

            String sign = CommonUtils.generateSignature(reqData, Constants.wxMerchantKey, "HMAC-SHA256");
            reqData.put("sign", sign);
            reqData.put("order_id", order_id);
            reqData.put("miniprogram_appid", Constants.wx_miniprogram_appid);
            reqData.put("miniprogram_path", Constants.wx_miniprogram_path);

            JSONObject objReq = new JSONObject();
            objReq.put("params", reqData);
            objReq.put("sn", sn);
            objReq.put("used_id", usedId);
            return BatteryJSONResult.build(1, "创建微信支付分订单", objReq);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("创建微信支付分订单失败");
        }
    }


    /**
     * 获取设备套餐内容
     *
     * @param storeInstall
     * @param amount
     * @return
     */
    private String getDevMealContent(StoreInstall storeInstall, BigDecimal amount) {
        String mealMsg = "";
        String freeMsg = "";
        if (storeInstall == null) {
            freeMsg = "前2分钟内免费,";
            BigDecimal price = new BigDecimal(2);
            mealMsg = mealMsg + freeMsg + price + "元/小时,日封20元,总封" + amount + "元";
        } else {
            if (storeInstall.getFreeM() > 0) {
                freeMsg = storeInstall.getFreeM() + "分钟内免费,";
            }
            if (DevMealTimeEnum.HALF_HOUR.type.intValue() == storeInstall.getUnitTime().intValue()) {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/半小时,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            } else if (DevMealTimeEnum.FIFTEEN_MINUTES.type.intValue() == storeInstall.getUnitTime().intValue()) {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/15分钟,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            } else {
                mealMsg = mealMsg + freeMsg + storeInstall.getPrice() + "元/小时,日封" + storeInstall.getDayMax() + "元,总封" + amount + "元";
            }
        }
        return mealMsg;
    }

    /**
     * @param out_order_no
     * @return
     */
    @Override
    public AuthUsed selectByOutOrderNo(String out_order_no) {
        Example example = new Example(AuthUsed.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("outOrderNo", out_order_no);
        return authUsedMapper.selectOneByExample(example);
    }

    /**
     * 租借失败，更新租借失败状态，同时撤销微信支付分订单
     *
     * @param used_id
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult doWxRevokeOrder(String used_id) {
        // 更新租借状态为租借失败

        Used used = usedMapper.selectByPrimaryKey(used_id);

        Used usedUpdate = new Used();
        usedUpdate.setId(used_id);
        usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode());
        usedUpdate.setStatus(UsedStatusEnum.REVOKE.getCode());
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        if (BorrowModeEnum.DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
            // 押金租借
            return BatteryJSONResult.build(2, "使用的是押金租借，无需撤销微信分订单！", null);
        }

        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);
        // 先查询微信支付分是否已经撤销
        if (UsedAuthStateEnum.REVOKED.type.equals(authUsed.getState()) && UsedAuthStateEnum.REVOKED.type.equals(authUsed.getStateDescription())) {
            // 该笔微信支付分订单已撤销
            return BatteryJSONResult.errorMsg("您的微信支付分授权订单已撤销！");
        }
        // 开始撤销微信支付分订单
        JSONObject obj = new JSONObject();
        obj.put("appid", Constants.wxMinAppID);
        obj.put("service_id", Constants.wxServiceId);
        obj.put("reason", "商家撤销订单"); // 商家撤销订单
        BatteryJSONResult response = null;
        try {
            response = PayscoreUtils.cancelbill(obj, authUsed.getOutOrderNo(), Constants.wxMerchantId, Constants.certSerialNo, Constants.wx_cret_keyPath_apiclient_key);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("撤销微信支付分失败");
        }
        if (response.getCode() == 0) {
            return response;
        }
        String body = (String) response.getData();
        JSONObject responseObj = JSON.parseObject(body);
        if (StringUtils.isNotBlank(responseObj.getString("code"))) {
            return BatteryJSONResult.build(1, "撤销微信支付分失败-失败原因：" + responseObj.getString("message"), null);
        }
        // 撤销微信支付分成功, 更新状态
        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(used_id);
        authUsedUpdate.setState(UsedAuthStateEnum.REVOKED.type);
        authUsedUpdate.setStateDescription(UsedAuthStateEnum.REVOKED.type); // 如果是微信支付分撤销
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        JSONObject requestJSON = new JSONObject();
        requestJSON.put("used_id", used_id);
        return BatteryJSONResult.build(1, "租借失败，对应的支付分订单已撤销！可重新发起租借", requestJSON);
    }

    /**
     * 查询用户是否点击确认
     *
     * @param authUsed
     * @param isOutOrderNo
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult queryrentbill(AuthUsed authUsed, boolean isOutOrderNo) {
        String out_order_no = authUsed.getOutOrderNo();
        JSONObject reqQuery = new JSONObject();
        reqQuery.put("service_id", Constants.wxServiceId);
        reqQuery.put("out_order_no", out_order_no);
        reqQuery.put("appid", Constants.wxMinAppID);
        BatteryJSONResult result = null;
        try {
            result = PayscoreUtils.queryrentbill(reqQuery, isOutOrderNo, Constants.wx_cret_keyPath_apiclient_key, Constants.wxMerchantId, Constants.certSerialNo);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("查询支付分订单发生错误，请联系管理员");
        }
        if (result == null) {
            return BatteryJSONResult.errorMsg("查询支付分订单发生错误，请联系管理员");
        }
        if (result.getCode() == 0) {
            return result;
        }
        String body = (String) result.getData();
        JSONObject obj_ = JSONObject.parseObject(body);
        String state = obj_.getString("state"); // 服务订单状态
        String state_description = obj_.getString("state_description"); // 服务订单状态
        if (UsedAuthStateEnum.DOING.type.equals(state)
                && UsedAuthStateDescriptionEnum.USER_CONFIRM.type.equals(state_description)) {
            AuthUsed authUsedUpdate = new AuthUsed();
            authUsedUpdate.setUsedId(authUsed.getUsedId());
            authUsedUpdate.setState(state);
            authUsedUpdate.setStateDescription(state_description);
            authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);
            return BatteryJSONResult.ok();
        }
        return BatteryJSONResult.errorMsg("微信分所处状态存在问题，请联系客服");
    }

    /**
     * 微信支付分零元结束订单
     *
     * @param authUsed
     * @return
     */
    @Transactional
    @Override
    public int wxfreeZeroPay(AuthUsed authUsed) {

        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(authUsed.getUsedId());
        authUsedUpdate.setState(UsedAuthStateEnum.PAID.type);
        authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.USER_PAID.type);
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        Used usedUpdate = new Used();
        usedUpdate.setId(authUsed.getUsedId());
        usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 更新租借订单为已支付
        usedUpdate.setPaymentTime(DateUtils.getNowDate());

        return usedMapper.updateByPrimaryKeySelective(usedUpdate);
    }

    /**
     * 微信支付分支付成功回调通知
     *
     * @param collectionJSON 收款信息，非0元完结后返回
     * @param authUsed       微信支付分授权订单
     * @return
     */
    @Transactional
    @Override
    public int wxfreePay(JSONObject collectionJSON, AuthUsed authUsed) {
        // 注意：暂时不处理待支付的订单
        String state = collectionJSON.getString("state"); // 收款状态
        if ("USER_PAID".equals(state)) {
            // USER_PAID：已支付
            BigDecimal total_amount = collectionJSON.getBigDecimal("total_amount").divide(new BigDecimal(100)); // 总收款金额
            BigDecimal paid_amount = collectionJSON.getBigDecimal("paid_amount").divide(new BigDecimal(100)); // 用户已付款的金额
            // 收款明细列表
            JSONArray detailsArr = collectionJSON.getJSONArray("details");

            // TODO TODO 全额支付才加入到支付订单表中 ，暂时不考虑未付款部分
            // TODO TODO 注意收款渠道
            if (total_amount.subtract(paid_amount).compareTo(BigDecimal.ZERO) == 0) {
                // 总收款金额 减去 用户已付款的金额 等于0，则代表用户已经全额付款
                int size = detailsArr.size();
                // 查询对应的租借订单
                Date date = DateUtils.getNowDate();


                String orderIdIsOne = "";
                Used used = usedMapper.selectByPrimaryKey(authUsed.getUsedId());
                for (int i = 0; i < size; i++) {
                    JSONObject detailObj = detailsArr.getJSONObject(i);
                    BigDecimal amount = detailObj.getBigDecimal("amount").divide(new BigDecimal(100));
                    String paid_type = detailObj.getString("paid_type"); // 收款成功渠道
                    String transaction_id = detailObj.getString("transaction_id"); // 结单交易单号--微信支付交易单号
                    String paid_time = detailObj.getString("paid_time"); // 收款成功时间

                    String orderId = sid.nextShort();
                    if (size == 1) {
                        orderIdIsOne = orderId;
                    }
                    Order order = new Order();
                    order.setId(orderId);
                    order.setChannel(used.getChannel());
                    order.setAppUserId(used.getAppUserId());
                    order.setTransactionId(transaction_id);
                    order.setTotalFee(amount);
                    order.setTradeState(OrderTradeStateEnum.PAY_SUCCESS.getCode());
                    order.setCreatedTime(date);
                    order.setPayTime(DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, paid_time));
                    order.setProjectId(used.getProjectId());
                    order.setPartnerId(used.getPartnerId());
                    order.setMerchantId(used.getMerchantId());
                    order.setStoreId(used.getStoreId());
                    order.setOrderType(OrderTypeEnum.DEV_BORROW_COST.type);
                    order.setPayType(OrderPayTypeEnum.WX_FREE.getCode());
                    order.setUsedId(authUsed.getUsedId()); // 保存订单ID
                    orderMapper.insertSelective(order);
                }

                // 更新租借订单状态
                Used usedUpddate = new Used();
                usedUpddate.setId(used.getId());
                Project project = projectMapper.selectByPrimaryKey(used.getProjectId());
                BigDecimal deposit = new BigDecimal(99);
                if (project != null) {
                    deposit = project.getDeposit();
                }
                if (deposit.subtract(paid_amount).compareTo(BigDecimal.ZERO) == 0) {
                    // 租借费用达到押金金额
                    usedUpddate.setStatus(UsedStatusEnum.PURCHASED.getCode());
                } else {
                    usedUpddate.setStatus(UsedStatusEnum.PAID.getCode());
                }
                usedUpddate.setPaymentTime(date);
                if (size == 1) {
                    usedUpddate.setTrueOrderId(orderIdIsOne);
                }
                // 因为微信支付分订单存在多笔支付订单，是一对多关系，所以不存储真实订单ID
                usedMapper.updateByPrimaryKeySelective(usedUpddate);

                AuthUsed authUsedUpdate = new AuthUsed();
                authUsedUpdate.setState(UsedAuthStateEnum.PAID.type);
                authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.USER_PAID.type);
                authUsedUpdate.setUsedId(authUsed.getUsedId());
                authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

                // TODO TODO 开始分润操作
                if (size == 1) {
                    // 进行分润操作
                    incomeService.shareMoney(authUsed.getUsedId(), orderIdIsOne);
                }

            }
        }
        return 1;
    }

    /**
     * 支付宝创建预授权订单
     *
     * @param appUser      用户信息
     * @param device       设备信息
     * @param storeInstall 门店配置信息
     * @param amount       冻结金额
     * @param entity       授权参数
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult doFreeze(AppUser appUser, Device device, StoreInstall storeInstall, BigDecimal amount, AliPayEntity entity) {

        String sn = device.getSn();
        String usedId = sid.nextShort();
        Date date = DateUtils.getNowDate();


        String order_number = GenerateSeqUtil.generateEndRadomCode();

        Used used = new Used();
        used.setId(usedId);
        used.setChannel(appUser.getUserType());// 订单渠道 微信 1 支付宝 2
//        used.setOrderNumber(GenerateSeqUtil.generateSeqNo()); // order_number
        used.setOrderNumber(order_number); // order_number
        used.setBorrowMode(BorrowModeEnum.FREE_DEPOSIT.type); // 免押租借
        used.setProjectId(device.getProjectId()); // 平台-项目ID
        used.setPartnerId(device.getPartnerId()); // 合作商
        used.setMerchantId(device.getMerchantId()); // 商户
        used.setStoreId(device.getStoreId());
        used.setAppUserId(appUser.getId());
        used.setCreateTime(date);

        String storeName = "";
        if (storeInstall != null) {
            Store store = storeMapper.selectByPrimaryKey(storeInstall.getStoreId());
            if (store != null) {
                storeName = store.getStoreName();
            }
        }
        used.setStoreName(storeName);
        Project project = projectMapper.selectByPrimaryKey(device.getProjectId());
        used.setMealContent(getDevMealContent(storeInstall, project.getDeposit()));
        used.setIsFree(appUser.getIsFree()); // VIP订单
        usedMapper.insertSelective(used);

        // 这里只是创建，而不是去租借
        UsedBasics basics = new UsedBasics();
        basics.setUsedId(usedId);
        basics.setRentDeviceId(device.getId());// 租借设备ID
        basics.setRentDeviceSn(sn); // 租借设备SN
        basics.setDevType(device.getDevType());
        usedBasicsMapper.insertUsedBasics(basics);

        AuthUsed authUsed = new AuthUsed();
        authUsed.setUsedId(usedId);
//        String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(12); // 商户授权资金订单号
        String outOrderNo = order_number; // 商户授权资金订单号
        String outRequestNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(12); // 商户本次资金操作的请求流水号，用于标示请求流水的唯一性
        authUsed.setOutOrderNo(outOrderNo);
        authUsed.setAmount(amount);
        authUsed.setTicket(outRequestNo); // TODO 注意： 商户本次资金操作的请求流水号，用于标示请求流水的唯一性
        authUsed.setCreateTime(date); // 免押订单创建时间
        authUsed.setAppUserId(appUser.getId());
        authUsedMapper.insertSelective(authUsed);
        try {
            String order_title = "免电-信用分授权";
            JSONObject requestFreeze = new JSONObject();
            requestFreeze.put("out_order_no", outOrderNo);
            requestFreeze.put("out_request_no", outRequestNo);
            requestFreeze.put("order_title", order_title);
            requestFreeze.put("amount", amount);
            requestFreeze.put("payee_logon_id", entity.getPayeeLogonId()); // 收款方支付宝账号（Email或手机号）
            requestFreeze.put("payee_user_id", entity.getPayeeUserId()); // 收款方的支付宝唯一用户号,以2088开头的16位纯数字组成
            requestFreeze.put("serviceId", entity.getServiceId()); // 芝麻信用服务ID
            requestFreeze.put("freezeNotifyUrl", entity.getFreezeNotifyUrl()); // 回调地址
            BatteryJSONResult generateFreezeResponse = AliPayUtils.generateFreeze(entity, requestFreeze);
            if (generateFreezeResponse.getCode().intValue() == 0) {
                return generateFreezeResponse;
            }
            AlipayFundAuthOrderAppFreezeResponse response = (AlipayFundAuthOrderAppFreezeResponse) generateFreezeResponse.getData();
            // 更新状态
            AuthUsed authUsedUpdate = new AuthUsed();
            authUsedUpdate.setUsedId(usedId);
            authUsedUpdate.setState(UsedAuthStateEnum.CREATED.type); // 商家创建授权订单
            // TODO
            authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

            JSONObject objReq = new JSONObject();
            objReq.put("params", response);
            objReq.put("used_id", authUsed.getUsedId());
            return BatteryJSONResult.build(1, "创建支付宝预授权订单", objReq);
        } catch (Exception e) {
            e.printStackTrace();
            return BatteryJSONResult.errorMsg("创建支付宝预授权订单失败");
        }
    }


    /**
     * 支付宝预授权订单解冻 -->
     *
     * @param used_id 租借订单
     * @return
     */
    @Override
    public BatteryJSONResult doUnfreeze(String used_id, AliPayEntity entity) {
        // 更新租借状态为租借失败
        Used used = usedMapper.selectByPrimaryKey(used_id);

        Used usedUpdate = new Used();
        usedUpdate.setId(used_id);
        usedUpdate.setLeaseState(LeaseStateEnum.FAIL.getCode());
        usedUpdate.setStatus(UsedStatusEnum.REVOKE.getCode());
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        if (BorrowModeEnum.DEPOSIT.type.intValue() == used.getBorrowMode().intValue()) {
            // 押金租借
            return BatteryJSONResult.build(2, "使用的是押金租借，无需撤销微信分订单！", null);
        }

        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);
        if (UsedAuthStateEnum.REVOKED.type.equals(authUsed.getState()) && UsedAuthStateEnum.REVOKED.type.equals(authUsed.getStateDescription())) {
            return BatteryJSONResult.errorMsg("您的预授权订单已撤销！");
        }

        String auth_no = authUsed.getAuthNo();
        String out_request_no = authUsed.getTicket();
        BigDecimal amount = authUsed.getAmount();
        BatteryJSONResult reponseResult = AliPayUtils.unfreeze(entity, auth_no, out_request_no, amount);
        if (reponseResult.getCode() == 0) {
            // 撤销失败
            JSONObject responseJSON = (JSONObject) reponseResult.getData();
            String subCode = responseJSON.getString("sub_code");
            if ("ORDER_ALREADY_FINISH".equals(subCode) || "ORDER_ALREADY_CLOSED".equals(subCode)) {
                // ORDER_ALREADY_FINISH --> 授权失败，本笔授权订单已经完结，无法再进行资金操作
                // ORDER_ALREADY_CLOSED	 --> 授权失败，本笔授权订单已关闭
                // TODO TODO 注意： 这两种状态表示授权订单已结束, 直接设置为撤销成功
                AuthUsed authUsedUpdate = new AuthUsed();
                authUsedUpdate.setUsedId(used_id);
                authUsedUpdate.setState(UsedAuthStateEnum.REVOKED.type); // 撤销订单
                authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.UNFREEZE.type); // 取消订单
                JSONObject requestJSON = new JSONObject();
                requestJSON.put("used_id", used_id);
                return BatteryJSONResult.build(1, "您的预授权订单已解冻", requestJSON);
            } else {
                JSONObject requestJSON = new JSONObject();
                requestJSON.put("used_id", used_id);
                return BatteryJSONResult.build(1, "对应的授权订单未成功解冻！请联系客服处理", requestJSON);
            }
        }
        // 解冻成功，更新状态
        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(used_id);
        authUsedUpdate.setState(UsedAuthStateEnum.REVOKED.type); // 撤销订单
        authUsedUpdate.setStateDescription(UsedAuthStateEnum.REVOKED.type); // 撤销订单
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        JSONObject requestJSON = new JSONObject();
        requestJSON.put("used_id", used_id);
        return BatteryJSONResult.build(1, "您的预授权订单已解冻", requestJSON);
    }


    /**
     * 支付宝预授权-授权回调通知
     *
     * @param authUsed 授权订单
     * @param response
     * @return
     */
    @Transactional
    @Override
    public String freezeCallback(AuthUsed authUsed, AlipayFundAuthOperationDetailQueryResponse response) {
        /**
         * 支付宝资金操作类型，
         * 目前支持：
         * FREEZE：冻结
         * UNFREEZE：解冻
         * PAY：支付
         */
        String operation_type = response.getOperationType();
        if ("FREEZE".equals(operation_type)) {
            // TODO TODO 暂时只考虑FREEZE
            String auth_no = response.getAuthNo();
            String operation_id = response.getOperationId();

            AuthUsed authUsedUpdate = new AuthUsed();
            authUsedUpdate.setUsedId(authUsed.getUsedId());
            authUsedUpdate.setPreAuthType(response.getPreAuthType());
            authUsedUpdate.setOperationId(operation_id);
            authUsedUpdate.setAuthNo(auth_no);
            authUsedUpdate.setState(UsedAuthStateEnum.DOING.type);
            authUsedUpdate.setStateDescription(UsedAuthStateDescriptionEnum.FREEZE.type);
            authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);
        }
        return "success";
    }

    /**
     * 微信免押订单列表
     *
     * @param usedBO
     * @return
     */
    @Override
    public List<UsedVO> wxAuthList(UsedBO usedBO) {
        return authUsedMapper.wxAuthList(usedBO);
    }

    /**
     * 微信支付分发起支付催款
     *
     * @param id 租借记录ID
     * @return
     */
    @Override
    public AjaxResult requestWxFreePay(String id) {
        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(id);
        JSONObject obj = new JSONObject();
        obj.put("appid", Constants.wxMinAppID);
        obj.put("service_id", Constants.wxServiceId);
        BatteryJSONResult response = null;
        try {
            response = PayscoreUtils.pay(obj, authUsed.getOutOrderNo(), Constants.wxMerchantId, Constants.certSerialNo, Constants.wx_cret_keyPath_apiclient_key);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("微信免押发起催款失败");
        }
        if (response.getCode() == 0) {
            return AjaxResult.error("微信免押发起催款失败");
        }
        String body = (String) response.getData();
        JSONObject responseObj = JSON.parseObject(body);
        if (responseObj.getString("out_order_no").equals(authUsed.getOutOrderNo())) {
            return AjaxResult.success("微信免押发起催款成功");
        }
        return AjaxResult.error("微信免押发起催款失败");
    }

    /**
     * 支付宝免押订单列表
     *
     * @param usedBO
     * @return
     */
    @Override
    public List<UsedVO> aliAuthList(UsedBO usedBO) {
        return authUsedMapper.aliAuthList(usedBO);
    }

    /**
     * 支付宝发起催款 TODO 到时候要多测试
     *
     * @param used_id
     * @return
     */
    @Override
    public AjaxResult requestAliFreePay(String used_id, AliPayEntity entity) {

        /**
         * 1、商户继续扣款
         * （1）扣款失败15天内使用完全相同的请求参数（即out_trade_no以及其他请求参数和第一次调用授权转支付的参数完全相同）再次调用授权转支付接口进行重试。
         *
         * （2）该订单一直无法扣款成功，商户需在订单的15天内调用订单关闭接口关闭订单（避免系统自动关单同步逾期），再修改out_trade_no重新扣款，直到扣款成功。
         */
        // 查询对应的授权订单
        AuthUsed authUsed = authUsedMapper.selectByPrimaryKey(used_id);
        Used used = usedMapper.selectByPrimaryKey(used_id);
        // 若授权转支付失败，商户可在 15 天内发起重试扣款，扣款时请保持交易订单号不变；
        // 若 15 天内尝试扣款失败，请调用支付宝 订单信息同步接口，反馈用户违约状态，芝麻届时会记录用户负面记录。
        // 暂时不考虑15天
        Order aliFreeNoPay = orderMapper.selectByPrimaryKey(used.getTrueOrderId());
        // 13天之内可以采用相同请求参数重新发起扣款， 如果超过13天则取消掉该笔订单，创建一笔新订单发起扣款
        Date nowDate = DateUtils.getNowDate();
        Date orderCreateDate = aliFreeNoPay.getCreatedTime();

        BigDecimal amount = used.getAmountPaid();

        String outTradeNo = "";
        if (DateUtils.differentDaysByMillisecond(nowDate, orderCreateDate) < 13) {
            // 小于13天
            // （1）扣款失败15天内使用完全相同的请求参数（即out_trade_no以及其他请求参数和第一次调用授权转支付的参数完全相同）再次调用授权转支付接口进行重试。
            outTradeNo = aliFreeNoPay.getOutOrderNo();
        } else {
            // 大于13天, 创建一笔新的订单
            // （2）该订单一直无法扣款成功，商户需在订单的15天内调用订单关闭接口关闭订单（避免系统自动关单同步逾期），再修改out_trade_no重新扣款，直到扣款成功。

            // ===================================
            // => 开始调起订单关闭接口关闭订单
            // ===================================
            BatteryJSONResult resultClose = AliPayUtils.tradeClose(entity, aliFreeNoPay.getTransactionId(), aliFreeNoPay.getOutOrderNo());
            if (resultClose.getCode() == 0) {
                // 调起订单关闭接口失败
                return AjaxResult.error(resultClose.getMsg());
            }
            // 旧订单成功关闭
            Order updateOldOrder = new Order();
            updateOldOrder.setId(aliFreeNoPay.getId());
            updateOldOrder.setTradeState(OrderTradeStateEnum.CLOSED.getCode()); // 订单已关闭
            orderMapper.updateByPrimaryKeySelective(updateOldOrder);


            aliFreeNoPay = new Order();
            String order_id = sid.nextShort();
            String outOrderNo = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
            aliFreeNoPay.setId(order_id);
            aliFreeNoPay.setAppUserId(used.getAppUserId());
            aliFreeNoPay.setProjectId(used.getProjectId());
            aliFreeNoPay.setPartnerId(used.getPartnerId());
            aliFreeNoPay.setMerchantId(used.getMerchantId());
            aliFreeNoPay.setStoreId(used.getStoreId());
            aliFreeNoPay.setOutOrderNo(outOrderNo);
            aliFreeNoPay.setChannel(used.getChannel());
            aliFreeNoPay.setTotalFee(amount);
            aliFreeNoPay.setTradeState(OrderTradeStateEnum.UNPAID.getCode()); // 未支付
            UsedBasics basics = usedBasicsMapper.selectByPrimaryKey(used_id);
            aliFreeNoPay.setCreatedTime(DateUtils.getNowDate());
            aliFreeNoPay.setSn(basics.getRentDeviceSn());
            aliFreeNoPay.setPayType(OrderPayTypeEnum.ZFB_FREE.getCode()); // 支付宝预授权
            aliFreeNoPay.setOrderType(OrderTypeEnum.DEV_BORROW_COST.type);
            aliFreeNoPay.setUsedId(used_id);
            orderMapper.insertSelective(aliFreeNoPay);

        }
        String authNo = authUsed.getAuthNo();
        String subject = "免电" + "充电宝订单支付";
        AppUser appUser = appUserMapper.selectByPrimaryKey(used.getAppUserId());
        BatteryJSONResult result = AliPayUtils.tradePay(entity, outTradeNo, authNo, subject, amount, appUser.getAppUserCode(), Constants.ali_freeze_pay_url);
        if (result.getCode() == 0) {
            // TODO 扣款失败，注意要记录对应的支付宝交易号
            AlipayTradePayResponse response = (AlipayTradePayResponse) result.getData();
            String trade_no = response.getTradeNo();
            if (StringUtils.isNotBlank(trade_no)) {
                Order updateOrder = new Order();
                updateOrder.setId(aliFreeNoPay.getId());
                updateOrder.setTransactionId(trade_no); // 支付宝交易号（支付失败的情况下，该订单号非常重要）
                orderMapper.updateByPrimaryKeySelective(updateOrder);
            }

            Used usedUpdate = new Used();
            usedUpdate.setId(used_id);
            usedUpdate.setTrueOrderId(aliFreeNoPay.getId());
            usedMapper.updateByPrimaryKeySelective(usedUpdate);

            return AjaxResult.error(result.getMsg());
        }
        AlipayTradePayResponse response = (AlipayTradePayResponse) result.getData();
        String trade_no = response.getTradeNo();

        // 授权订单完成
        AuthUsed authUsedUpdate = new AuthUsed();
        authUsedUpdate.setUsedId(used_id);
        authUsedUpdate.setState(UsedAuthStateEnum.DONE.type);
        authUsedMapper.updateByPrimaryKeySelective(authUsedUpdate);

        Used usedUpdate = new Used();
        usedUpdate.setId(used_id);
        usedUpdate.setTrueOrderId(aliFreeNoPay.getId());
        usedMapper.updateByPrimaryKeySelective(usedUpdate);

        Order updateOrder = new Order();
        updateOrder.setId(aliFreeNoPay.getId());
        updateOrder.setTransactionId(trade_no);
        orderMapper.updateByPrimaryKeySelective(updateOrder);
        return AjaxResult.success();
    }


    /**
     * 查询该用户发起免押租借但是未确认的订单数
     *
     * @param appUserId
     * @param lastMonth
     * @return
     */
    @Override
    public Integer selectCountNoAuth(String appUserId, Date lastMonth) {
        Example example = new Example(AuthUsed.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appUserId", appUserId);
        criteria.andGreaterThan("createTime", lastMonth);
        criteria.orIsNull("state");
        criteria.orEqualTo("state", UsedAuthStateEnum.CREATED.type);
        return authUsedMapper.selectCountByExample(example);
    }
}
